`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:xzh 
// 
// Create Date: 2020/10/08 19:56:19
// Design Name: 
// Module Name: width_64_conver_256_data_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description:\u4f4d\u5bbd\u8f6c\u5316,\u5728\u6d41\u7247\u60c5\u51b5\u4e0b\u7528ram IP\u52a0\u5916\u56f4\u903b\u8f91\u6a21\u62df\u4f4d\u5bbd\u8f6c\u5316\u7684sync_fifo\uff0c\u4ec5\u5c0f\u4f4d\u5bbd\u8f6c\u5927\u4f4d\u5bbd\uff0c\u8f6c\u6362\u6bd4\u4e3a2,4,8...
//              parameter\u5176\u5b9e\u4e0d\u662f\u771f\u6b63\u7684"parameter"\u53ea\u662f\u4e3a\u4e86\u65b9\u4fbf,\u5982\u679c\u6539parameter\u9700\u8981\u5bf9\u90e8\u5206\u4ee3\u7801(--XXXX--)\u8fdb\u884c\u4fee\u6539 
//              
//              \u4fee\u6539\u4f7f\u5176\u5bf9\u5e94AXI_stream\u683c\u5f0f
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module axi_width_64_conver_256_data_fifo  #( parameter DEPTH = 95 , ADDR = 7 , ALMOST_FULL = 94 , 
	                          WIDTH_IN = 75 , WIDTH_OUT = 300 , MULTI = 4 , MULTI_ADDR = 2)
(
	input clk ,
	input rst_n ,
    input [9:0]ram_2p_cfg_register,
	input frame_end ,//\u5199\u4e00\u6b21\uff0c\u6240\u4ee5\u53ef\u80fd\u4f1a\u4f7f\u4e24\u4e2a\u5e27\u5408\u5728\u540c\u4e00\u6b21\u6570\u636e\u4e2d\uff0c\u8fd9\u662f\u4e0d\u884c\u7684\uff0c\u5916\u56f4\u5199\u7684\u65f6\u5019\u8865\u96f6,\u4f46\u8865\u96f6\u7684\u6b21\u6570\u4e3a0-MULTI-1\uff0c
	                 //\u8017\u65f6\u53ef\u80fd\u8f83\u5927\uff0c\u6240\u4ee5\u7528\u8be5\u4fe1\u53f7\u4e00\u6b21\u8865\u591a\u4e2a\u96f6,\u5bf9\u5e94axi_stream tlast
	//w
	input  fifo_wr_en ,
	input  [WIDTH_IN-1:0] fifo_data_in ,
	output reg fifo_full_wr ,
	output reg almost_full ,
    
    //r
    input fifo_rd_en ,
    output reg[WIDTH_OUT-1:0] fifo_data_out ,
    output reg fifo_empty_rd 
);



//REG 
//W
reg     [        ADDR:   0]   wr_bin                   ; 

reg                           ram_wr_en                ; 
reg     [WIDTH_OUT-1:    0]   ram_wdata                ; 
reg     [      ADDR-1:   0]   ram_wadder               ; 

reg     [MULTI_ADDR-1:   0]   write_cnt                ; 

//R
reg     [       ADDR:    0]    rd_bin                  ; 
 
wire                           ram_rd_en               ; 
wire    [WIDTH_OUT-1:    0]    ram_rdata               ; 
wire    [     ADDR-1:    0]    ram_radder              ; 

//empty/full
reg     [        ADDR:   0]   data_cnt                 ;
reg     fifo_full_wr_real                              ; //\u6b63\u771f\u6ee1,\u4e0e\u5199\u540c\u6b65
reg     fifo_empty_rd_real                             ;

//----------------------------------------------
//W_CTRL
//----------------------------------------------
//\u5199\u8ba1\u6570,\u7d2f\u8ba1\u4f4d\u5bbd\u8f6c\u6362\u500d\u6570\u6b21/frame_end,\u5199\u4e00\u6b21\uff0c
always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
		write_cnt <= 'd0 ; 
	else if ( frame_end == 1'b1 && fifo_wr_en == 1'b1 && fifo_full_wr_real == 1'b0)
		write_cnt <= 'd0 ; 
	else if ( fifo_wr_en == 1'b1 && fifo_full_wr_real == 1'b0 ) 
		if ( write_cnt == MULTI - 1 )
			write_cnt <= 'd0 ; 
		else
			write_cnt <= write_cnt + 'd1 ;  
	else 
		write_cnt <= write_cnt ; 
end 

//\u76f4\u63a5\u8fde\u63a5ram\u7684\u5199\u4f7f\u80fd\u4fe1\u53f7
always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
		ram_wr_en <= 1'b0 ; 
	else if ( ( write_cnt == MULTI - 1 || frame_end == 1'b1 ) && fifo_full_wr_real == 1'b0  && fifo_wr_en == 1'b1 )
		ram_wr_en <= 1'b1 ; 
	else
		ram_wr_en <= 1'b0 ; 
end


//--XXXX--//\u76f4\u63a5\u8fde\u63a5ram\u7684\u5199\u6570\u636e,\u5982\u679c\u6539\u53d8\u500d\u6570\u8fd9\u90e8\u5206\u9700\u8981\u6539\u53d8
always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
		ram_wdata <= 'b0 ; 
	else if ( fifo_wr_en == 1'b1 && fifo_full_wr_real == 1'b0 ) 
		case(write_cnt)
		    2'd0 : ram_wdata <= { fifo_data_in , {((MULTI-1)*WIDTH_IN){1'b0}} } ; 
		    2'd1 : ram_wdata <= { ram_wdata[WIDTH_OUT-1:(MULTI-1)*WIDTH_IN] , fifo_data_in ,ram_wdata[2*WIDTH_IN-1:0] } ; 
		    2'd2 : ram_wdata <= { ram_wdata[WIDTH_OUT-1:(MULTI-2)*WIDTH_IN] , fifo_data_in ,ram_wdata[1*WIDTH_IN-1:0] } ; 
		    2'd3 : ram_wdata <= { ram_wdata[WIDTH_OUT-1:(MULTI-3)*WIDTH_IN] , fifo_data_in } ; 
		    default:ram_wdata <= ram_wdata ;
		endcase
	else
		ram_wdata <= ram_wdata ;
end 

//wr_bin
always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
		wr_bin <= 'd0 ;
	else if ( ( write_cnt == MULTI - 1 || frame_end == 1'b1 ) && fifo_full_wr_real == 1'b0  && fifo_wr_en == 1'b1 ) begin
		if ( wr_bin[ADDR-1:0] == DEPTH-1 )
			wr_bin <= { ~wr_bin[ADDR] , {ADDR{1'b0}} } ;
		else  
			wr_bin <= wr_bin + 'b1 ; 
	end 
	else
		wr_bin <= wr_bin ; 
end 

//\u76f4\u63a5\u8fde\u63a5ram\u7684\u5199\u5730\u5740
//assign  ram_wadder = wr_bin[ADDR-1:0] ;

always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
		ram_wadder <= 'b0 ;
	else if ( ( write_cnt == MULTI - 1 || frame_end == 1'b1 ) && fifo_full_wr_real == 1'b0  && fifo_wr_en == 1'b1 )  
		ram_wadder <= wr_bin[ADDR-1:0] ;
	else  
		ram_wadder <= ram_wadder ;
end

//----------------------------------------------
//R_CTRL
//----------------------------------------------

always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
        rd_bin <= 'b0;
    else if ( fifo_rd_en == 1'b1 && fifo_empty_rd_real == 1'b0 ) begin
        if ( rd_bin[ADDR-1:0] == DEPTH - 1 )
            rd_bin <= { ~rd_bin[ADDR] , {ADDR{1'b0}} } ;
        else
            rd_bin <= rd_bin + 1'b1;
    end
    else
        rd_bin <= rd_bin;
end

//ram\u8bfb\u6570\u636e
//assign fifo_data_out =  ram_rdata ;   
//ASIC SRAMÊä³ö´òÒ»ÅÄ 
always @(posedge clk or negedge rst_n) begin
  	if(~rst_n) begin
  		fifo_data_out <= 0;
  	end 
  	else begin
  		fifo_data_out <= ram_rdata;
  	end
end  
//ram\u8bfb\u5730\u5740,\u4e0d\u5305\u62ecFIFO\u5199\u5730\u5740\u7684\u6700\u9ad8\u4f4d
assign ram_radder = rd_bin [ADDR-1:0];

//ram\u8bfb\u4f7f\u80fd
assign ram_rd_en = ( fifo_empty_rd_real == 1'b0 )? fifo_rd_en : 1'b0 ;


//----------------------------------------------
//data_cnt
//----------------------------------------------
always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
		data_cnt <= 'd0 ;
	else if ( ram_wr_en == 1'b1 && ram_rd_en == 1'b1 )  
		data_cnt <= data_cnt ;
	else if ( ram_wr_en == 1'b1 )   
		data_cnt <= data_cnt + 1 ;
 	else if ( ram_rd_en == 1'b1 )  
 		data_cnt <= data_cnt - 1 ;
 	else  
 		data_cnt <= data_cnt ;
end

//----------------------------------------------
//FULL/ALMOST_FULL
//----------------------------------------------
//FIFO\u6b63\u771f\u6ee1\u6807\u5fd7
always @ (rd_bin or wr_bin)
begin
    if( ( rd_bin[ADDR] != wr_bin[ADDR] ) && ( rd_bin[ADDR-1:0] == wr_bin[ADDR-1:0] ) )
        fifo_full_wr_real = 1'b1;
    else
        fifo_full_wr_real = 1'b0;
end

//FIFO\u6ee1\u6807\u5fd7,\u63d0\u65e9\u4e00\u4e2aclk,\u7528\u4e8e\u5916\u90e8\u7684\u65f6\u5e8f\u903b\u8f91\u5199,\u4e0d\u4f1a\u6ea2\u51fa
always @ ( * )
begin
    if ( ram_rd_en == 1'b0 && ram_wr_en == 1'b1 && data_cnt == DEPTH - 1 )
        fifo_full_wr = 1'b1 ;
    else
        fifo_full_wr = fifo_full_wr_real ;
end

//almost_full
always @(*) begin
	if ( data_cnt >= ALMOST_FULL ) 
    	almost_full = 1'b1 ;
    else  
        almost_full = 1'b0 ;
end

//----------------------------------------------
//EMPTY
//----------------------------------------------
//FIFO\u7a7a\u6807\u5fd7,\u63d0\u65e9\u4e00\u4e2aclk,\u7528\u4e8e\u5916\u90e8\u7684\u65f6\u5e8f\u903b\u8f91\u8bfb,\u4e0d\u4f1a\u8bfb\u7a7a
always @ ( * )
begin
    if ( ram_wr_en == 1'b1 )
        fifo_empty_rd = 1'b0 ;
    else if ( ram_wr_en == 1'b0 && ram_rd_en == 1'b1 && ( ( rd_bin[ADDR-1:0] == wr_bin[ADDR-1:0] - 1 && rd_bin[ADDR] == wr_bin[ADDR] ) 
                                      || ( rd_bin[ADDR] != wr_bin[ADDR] && wr_bin[ADDR-1:0] == 0 && rd_bin[ADDR-1:0] == DEPTH -1 ) ) )
        fifo_empty_rd = 1'b1 ;
    else
        fifo_empty_rd = fifo_empty_rd_real ;
end


//\u771f\u6b63\u7a7a
always @( posedge clk or negedge rst_n )
begin
	if ( rst_n == 1'b0 )
        fifo_empty_rd_real <= 1'b1 ;
    else if ( ram_wr_en==1'b1 )
    	fifo_empty_rd_real <= 1'b0 ;
    else if ( ram_wr_en == 1'b0 && ram_rd_en == 1'b1 && ( ( rd_bin[ADDR-1:0] == wr_bin[ADDR-1:0] - 1 && rd_bin[ADDR] == wr_bin[ADDR] ) 
                                      || ( rd_bin[ADDR] != wr_bin[ADDR] && wr_bin[ADDR-1:0] == 0 && rd_bin[ADDR-1:0] == DEPTH -1 ) ) ) 
        fifo_empty_rd_real <= 1'b1 ;
    else
        fifo_empty_rd_real <= fifo_empty_rd_real ;
end


//----------------------------------------------
//SUB_MODULE
//----------------------------------------------
//WIDTH_OUT
ram_2p_d96_w300_wrapper  U_ram_2p_d96_w300_wrapper  (
    .clk                   (clk                    ), // input wire clocka
    .ram_2p_cfg_register(ram_2p_cfg_register),
    .wren                  (ram_wr_en              ), // input wire [0 : 0] wea
    .waddr                (ram_wadder             ), // input wire [6 : 0] addra
    .wdata                 (ram_wdata              ), // input wire [127 : 0] dina
    .rden                  (ram_rd_en              ),
    .raddr                (ram_radder             ), // input wire [6 : 0] addrb
    .rdata                (ram_rdata              )  // output wire [127 : 0] doutb
);




endmodule

